import isFunction from 'lodash/isEmpty'

type NoticeType = 'info' | 'error' | 'success' | 'warning'
interface NoticeData {
  title: string
  content: string
}

type NoticeListener = (
  type: NoticeType,
  data: NoticeData,
  { next: onNext }
) => any
type NoticeTrigger = (data: NoticeData) => void

interface IQueueItem {
  type: NoticeType
  data: NoticeData
}

interface IQueueNotice {
  queue: Array<IQueueItem>
  current?: null | IQueueItem
  listener: NoticeListener
  init: (listener: NoticeListener) => void
  info: NoticeTrigger
  error: NoticeTrigger
  success: NoticeTrigger
  warning: NoticeTrigger
}

function isSame(a: NoticeData, b: NoticeData): boolean {
  return a.title === b.title && a.content === b.content
}

function onNext(notice: IQueueNotice): void {
  notice.current = notice.queue.shift()
  if (notice.current) {
    const {
      type,
      data
    } = notice.current
    try {
      notice.listener(type, data, {
        next: () => onNext(notice)
      })
    // eslint-disable-next-line no-empty
    } catch (e) {}
  }
}

function addNotice(type: NoticeType, data: any, notice: IQueueNotice) {
  if (data != null) {
    const {
      queue,
      current
    } = notice
    if (!((current != null ? isSame(current.data, data) : false)
      || queue.some(({ data: item }) => isSame(item, data)))) {
      queue.push({
        type,
        data
      })
    }
    if (current == null) {
      onNext(notice)
    }
  }
}

const QueueNotice: IQueueNotice = {
  queue: [],
  listener: () => {},
  init: (listener) => {
    QueueNotice.listener = listener
  },

  info(data) {
    addNotice('info', data, QueueNotice)
  },
  error(data) {
    addNotice('error', data, QueueNotice)
  },
  success(data) {
    addNotice('success', data, QueueNotice)
  },
  warning(data) {
    addNotice('warning', data, QueueNotice)
  }
}

export default QueueNotice
